#include "cam_socket.h"
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <string>
#include <iostream>
#include <netinet/in.h>
#include <string.h>
#include <arpa/inet.h>
#include<sys/epoll.h>
int g_loc_client_socket = -1;
static pthread_t handleThread;

#define MAX_BUF_SIZE 1024
#define MAX_SOKCET_FD 100


#define CAM_UDP_SERVER_PORT 55555
#define CAM_UDP_CLIENT_PORT 1114
// #define CAMERA_IP_ADDRESS "192.168.144.63"
// #define LOCAL_IP_ADDRESS "192.168.144.66"
#define CAMERA_IP_ADDRESS "192.168.137.63"
#define LOCAL_IP_ADDRESS "192.168.137.232"

int SendDataByUDP(unsigned char *buf, int len)
{

    struct sockaddr_in server;
    bzero(&server,sizeof(server));
    server.sin_family=AF_INET;
    server.sin_port=htons(CAM_UDP_SERVER_PORT);
    server.sin_addr.s_addr=inet_addr(CAMERA_IP_ADDRESS);
    sendto(g_loc_client_socket,buf,len,0,(const struct sockaddr*)&server,sizeof(server));

    return 0;
}

int RecvDataByUDP(int socketfd, unsigned char *buf)
{
    struct sockaddr_in temp;
    socklen_t templen=sizeof(temp);
    ssize_t s=recvfrom(socketfd,buf,MAX_BUF_SIZE,0,(struct sockaddr*)&temp,&templen);
    if(s>0)
    {
        buf[s]=0;
    }

    return s;
}

void* recv_message_handler(void *context)
{
    int sockfd, len;
    int ret = -1;
    struct sockaddr_in dest;
    //char buffer[MAXBUF + 1];
    unsigned char buf[MAX_BUF_SIZE + 1];
    int epfd = -1;
    int recvfd,fd_ret;
    int i = 0;
    struct epoll_event ev;
    struct epoll_event events[MAX_SOKCET_FD] = {0};
    epfd = epoll_create(MAX_SOKCET_FD);
    sockfd = g_loc_client_socket;
    ev.data.fd = sockfd;
    ev.events = EPOLLIN | EPOLLOUT | EPOLLRDHUP;
    epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd, &ev);

    //Continuously receive data and print, input data can be sent
    while(1)
    {
        fd_ret = epoll_wait(epfd, events, 10, 200);
        if(fd_ret == 0)
        {
            continue;
        }
        else
        {
            for (i = 0; i < fd_ret; i++)
            {
                recvfd = events[i].data.fd;
                if ((events[i].events & EPOLLIN))
                {
                    if(events[i].data.fd ==  g_loc_client_socket)
                    {
                        bzero(buf, MAX_BUF_SIZE + 1);

                        len = RecvDataByUDP(g_loc_client_socket,buf);
                        if (len > 0)
                        {
                            printf(" recv data success %d bytes,data: ",len);
                            for(int j = 0; j < len; j++)
                            {
                                printf("%02x ", buf[j]);
                            }
                            printf("\n");

                        }
                        else
                            printf("data recv error !errno is %d,error message is'%s'\n",  errno, strerror(errno));

                    }
                }

            }
        }

    }
}

int CreateThread(void)
{

    pthread_attr_t attr;
    int rc = 0;
    rc = pthread_attr_init(&attr);
    if (rc)
    {
        printf("Error, init thread attribute failed(rc = %d).,%d ,%d\n", rc,0,0);
        return -1;
    }
    else
    {
        //According to FIBOCOM programming specifications, every if has a else. You can do your else work here
    }
    rc = pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);
    if (rc)
    {
        printf("Error, set setdetachstate failed(rc = %d).,%d ,%d\n", rc,0,0);
        return rc;
    }
    else
    {
        //According to FIBOCOM programming specifications, every if has a else. You can do your else work here
    }

    rc = pthread_create(&handleThread, &attr, recv_message_handler, NULL);
    if (rc)
    {
        printf("Error, create thread failed(rc = %d).,%d ,%d\n", rc,0,0);
        return rc;
    }
    else
    {
        //According to FIBOCOM programming specifications, every if has a else. You can do your else work here
    }
    return 0;

}
int init_socket(void)
{
    int ret = -1;
    int sockfd;
    struct sockaddr_in local_addr;
    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd < 0)
    {
        printf("Error, create socket failed,%d ,%d\n",0,0);
        return -1;
    }
    else
    {
        //According to FIBOCOM programming specifications, every if has a else. You can do your else work here
    }

    local_addr.sin_family = AF_INET;
    local_addr.sin_port = htons(CAM_UDP_CLIENT_PORT);
    local_addr.sin_addr.s_addr = INADDR_ANY;
    // local_addr.sin_addr.s_addr=inet_addr(LOCAL_IP_ADDRESS);

    ret = bind(sockfd, (struct sockaddr*)&local_addr, sizeof(local_addr));
    if (ret < 0)
    {
        perror("bind() failed");
        close(sockfd);
        return -1;
    }
    g_loc_client_socket = sockfd;
    return 0;
}

int cam_socket_init(void)
{
    //backup
    int err_code;
    int ret;
    ret = init_socket();
    if(0 == ret)
    {
        CreateThread();
    }
    else
    {
        return -1;
    }
    return 0;
}


